package com.bonc.apim.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bonc.apim.constant.BaseConstant;
import com.bonc.apim.dao.PublishDao;
import com.bonc.apim.dao.RecordDao;
import com.bonc.apim.dao.SubscribeDao;
import com.bonc.apim.entity.JsonResult;
import com.bonc.apim.entity.Publish;
import com.bonc.apim.entity.Record;
import com.bonc.apim.entity.Subscribe;
import com.bonc.apim.utils.WebClientUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * API审核功能
 * @author wishes
 */
@Controller
@RequestMapping("/sub")
public class SubscribeController {

	private static final Log log = LogFactory.getLog(SubscribeController.class);

	@Value("${processDefinitionId}")
	private String processDefinitionId;

    @Value("${publishModelKey}")
    private String publishModelKey;

	@Value("${bpmStartProcessURL}")
	private String bpmStartProcessURL;

	@Value("${bpmCompleteTaskURL}")
	private String bpmCompleteTaskURL;

	@Value("${bpmIframeNameUrl}")
	private String bpmIframeNameUrl;

	@Value("${bpmTrackURL}")
	private String bpmTrackURL;

	@Value("${apimURL}")
	private String apimURL;

	@Value("${tenantId}")
	private String tenantId;

	@Value("${subscribMode}")
	private Integer subscribMode;

	@Value("${iframeNameForBCMUrl}")
	private String iframeNameForBCMUrl;

	@Value("${bconsoleURL}")
	private String bconsoleURL;

	@Value("${portalURL}")
	private String portalURL;

	@Value("${enableBconsole}")
	private boolean enableBconsole;

	@Autowired
	private SubscribeDao subDao;

	@Autowired
	private RecordDao recordDao;

	@Autowired
	private PublishDao publishDao;

	/**
	 * 启动流程
	 */
	@RequestMapping("/startProcess")
	@ResponseBody
	public Object startProcess(String providerName, String apiName, String version, String tier, String subscriber,
							   String applicationId, String applicationName, String tenant_id, String callback) {
		long startTime = new Date().getTime();
		log.info("startProcess");
		/* 如果API状态不是审核中，则重新启动订阅流程 */
		List<Subscribe> subInfoList = subDao.findByProviderNameAndApiNameAndVersionAndTierAndSubscriberAndApplicationIdAndApiApproveStatus(
				providerName, apiName, version, tier, subscriber, applicationId,BaseConstant.API_APPROVING);
		if (!CollectionUtils.isEmpty(subInfoList)) {
			return buildReturn(callback, new JsonResult("流程正在审核中", BaseConstant.RETURN_CODE_EXISTED));
		}
		Subscribe subscribe = new Subscribe();
		subscribe.setTenantId(tenant_id);
		//tenant_id = (subscribMode==0?tenant_id:tenantId);
		subscribe.setProviderName(providerName);
		subscribe.setApiName(apiName);
		subscribe.setVersion(version);
		subscribe.setTier(tier);
		subscribe.setSubscriber(subscriber);
		subscribe.setApplicationId(applicationId);
		subscribe.setApplicationName(applicationName);
		subscribe.setApiApproveStartTime(new Date());
		subscribe.setApiApproveStatus(BaseConstant.API_APPROVING);// 状态
		subDao.save(subscribe);
		long saveTime = new Date().getTime();
		log.info("保存sub数据耗时： = " + (saveTime-startTime));
		/** 获取bpm流程启动返回流程实例id */
		String jsonData = null;
		try {
			jsonData = WebClientUtil.doGet(bpmStartProcessURL + "?modelKey=" + processDefinitionId + "&loginId="
					+ subscriber + "&subInfoId=" + subscribe.getId() + "&providerName="+providerName +"&tenant_id=" + tenantId + "&subTenant=" + ("admin".equals(subscribe.getSubscriber())?tenantId:subscribe.getTenantId()), null);
//			TODO	下次修改时在启动流程时添加脚本调用url地址方便修改
			JSONObject jsonObject = JSON.parseObject(jsonData);
			subscribe.setProInsId( (String) jsonObject.get("processInstanceId"));
			long sendTime1 = new Date().getTime();
			log.info("启动流程耗时： = " + (sendTime1-saveTime));
			subDao.save(subscribe);
			log.info("tenant_id=" + tenant_id);

			if (enableBconsole) {
				String svcName="API订阅审核";
				String jsonData1 = WebClientUtil.doGet(bconsoleURL +"/v1/tenantId/" +tenant_id + "/loginId/" + subscriber + "/bpmInstance"
						+ "?svcCode=" + processDefinitionId + "&svcName=" + URLEncoder.encode(svcName, "utf-8") + "&processInstanceId="
			+subscribe.getProInsId(), null);

				JSONObject jsonObject1 = JSON.parseObject(jsonData1);

				log.info("enableBconsole-jsonObject=" + jsonObject1);
			}
			long sendTime2 = new Date().getTime();
			log.info("Bconsole 接口耗时： = " + (sendTime2-sendTime1));
			//如果流程启动失败，删除不完整的数据
//			if (StringUtils.isEmpty((String)jsonObject.get("processInstanceId")) ) {
//				subDao.delete(subscribe.getId());
//				return buildReturn(callback, new JsonResult("审核流程启动失败，请联系管理员", BaseConstant.RETURN_CODE_ERROR));
//			}else {
//				subscribe.setProInsId( (String) jsonObject.get("processInstanceId"));
//				subDao.save(subscribe);
//				System.out.println("tenant_id=" + tenant_id);
//			}
		} catch (Exception e) {
			// 流程启动失败后，删除添加的数据
			subDao.delete(subscribe.getId());
			log.error("the process start is fail,response:"+jsonData , e);
			return buildReturn(callback, new JsonResult("审核流程启动失败，请联系管理员", BaseConstant.RETURN_CODE_ERROR));
		}
		return buildReturn(callback, new JsonResult("新的流程启动成功", BaseConstant.RETURN_CODE_OK));
	}

	/**
	 * 办理审核流程
	 * @param flowInstId 流程实例id
	 * @param taskId 当前流程任务id
	 * @param approvalOrlookFlag 办理或办理成功后查看 标志
	 * @return
	 */
	@RequestMapping("/approveApi")
	public ModelAndView approveApi(String flowInstId, String taskId, String approvalOrlookFlag, String user, String tenant_id, String task_key) {
		log.info("approveApi");
		Subscribe subInfo = subDao.findByProInsId(flowInstId);
		List<Record> recordList = recordDao.findByProInsId(flowInstId);
		//tenant_id = (subscribMode==0?tenant_id:tenantId);
		ModelAndView model = new ModelAndView();
		model.addObject("proInsId", flowInstId);
		model.addObject("taskId", taskId);
		model.addObject("subInfo", subInfo);
		model.addObject("recordList", recordList);
		model.addObject("loginUser", user);
		log.debug(model.toString());
		/** 判断bpm工单是跳往办理页面或者查看页面 */
		if ("approval".equals(approvalOrlookFlag)) {
			model.setViewName("apiapproval.jsp");
		} else if ("look".equals(approvalOrlookFlag)) {
			model.setViewName("apiapplyscan.jsp");
		}
		return model;
	}

	/**
	 * 完成任务节点
	 * @param proInsId 流程id
	 * @param taskId 任务id
	 * @param approvalSumup 提交同意(1 pass)，不同意(0 nopass)
	 * @param remark 审批意见
	 * @return
	 */
	@RequestMapping("/completeTask")
	public String completeTask(String proInsId, String taskId, String approvalSumup, String remark, String user) {
		log.info("completeTask");
		Subscribe subscribe = subDao.findByProInsId(proInsId);
		if (BaseConstant.APPROVAL_PASS == Integer.valueOf(approvalSumup)) {
			String ru = WebClientUtil.doGet(
					bpmCompleteTaskURL + "?taskId=" + taskId + "&action=pass" + "&loginId=" + user + "&tenant_id=" + subscribe.getTenantId() , null);
			log.debug("completeTask1 ru = "+ru);
			subscribe.setApiApproveStatus(BaseConstant.API_APPROVED_PASS);// 更新API审核状态:同意
			//给bconsole返回状态
			if (enableBconsole) {
				String jsonData = WebClientUtil.doGet(bconsoleURL +"/v1/tenantId/" +subscribe.getTenantId() + "/loginId/" + user + "/bpmProcess" + "?agreement=1&processInstanceId="
			+subscribe.getProInsId(), null);

				JSONObject jsonResult = JSON.parseObject(jsonData);
				if (!jsonResult.getBooleanValue("success")) {
					return "redirect:" + portalURL;
				}
				log.info("enableBconsole-jsonObject=" + jsonResult);
			}
			subDao.save(subscribe);
			addRecord(subscribe, taskId, remark, BaseConstant.APPROVAL_PASS, user);
		} else if (BaseConstant.APPROVAL_NOPASS == Integer.valueOf(approvalSumup)) {
			String ru = WebClientUtil.doGet(
					bpmCompleteTaskURL + "?taskId=" + taskId + "&action=nopass" + "&loginId=" + user +"&tenant_id=" + subscribe.getTenantId(),
					null);
			log.debug("completeTask2 ru = "+ru);
			subscribe.setApiApproveStatus(BaseConstant.API_APPROVED_NOPASS);// 更新API审核状态:不同意
			//给bconsole返回状态
			if (enableBconsole) {
				String jsonData  = WebClientUtil.doGet(bconsoleURL +"/v1/tenantId/" +subscribe.getTenantId() + "/loginId/" + user + "/bpmProcess" + "?agreement=0&processInstanceId="
			+subscribe.getProInsId(), null);

				JSONObject jsonResult = JSON.parseObject(jsonData);
				if (!jsonResult.getBooleanValue("success")) {
					return "redirect:" + portalURL;
				}
				log.info("enableBconsole-jsonObject=" + jsonResult);
			}
			subDao.save(subscribe);
			addRecord(subscribe, taskId, remark, BaseConstant.APPROVAL_NOPASS, user);
		}
		return "redirect:" + portalURL;
	}

	/**
	 * 调用脚本   通过
	 * @param subInfoId 主键
	 * @return
	 * @throws IOException
	 */
	@RequestMapping("/apimInvokePass")
	public void apimInvokePass(long subInfoId) {

		log.info("bpm js process  invoke: pass " + subInfoId);
		Subscribe subscribe = subDao.findById(subInfoId);
		try {
			String url = apimURL + "?name=" + URLEncoder.encode(subscribe.getApiName(),"UTF-8") + "&version=" + subscribe.getVersion()
					+ "&provider=" + subscribe.getProviderName() + "&applicationId=" + subscribe.getApplicationId()
					+ "&tier=" + subscribe.getTier() + "&subscriber=" + subscribe.getSubscriber() + "&status=pass" + "&pinsid=" + subscribe.getProInsId();
			String jsonData = WebClientUtil.doGet(url, null);
            subscribe.setApiApproveEndTime(new Date());
			subscribe.setApiApproveStatus(BaseConstant.API_APPROVED_PASS);// 更新API审核状态:同意
            subDao.save(subscribe);
			log.debug("apim invoke request---------------------" + url);
			log.debug("apim invoke response--------------------" + jsonData);
		}
		catch (UnsupportedEncodingException e) {
			log.error("apim encode api name error");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//return "redirect:"+iframeNameForBCMUrl;
	}

	/**
	 * 脚本调用  不通过
	 * @return
	 */
	@RequestMapping("/apimInvokeNoPass")
	public void apimInvokeNoPass(long subInfoId) {

		log.info("bpm js process  invoke: nopass " + subInfoId);
		Subscribe subscribe = subDao.findById(subInfoId);
		try {
			String url = apimURL + "?name=" + URLEncoder.encode(subscribe.getApiName(),"UTF-8") + "&version=" + subscribe.getVersion()
					+ "&provider=" + subscribe.getProviderName() + "&applicationId=" + subscribe.getApplicationId()
					+ "&tier=" + subscribe.getTier() + "&subscriber=" + subscribe.getSubscriber() + "&status=nopass" + "&pinsid=" + subscribe.getProInsId();
			String jsonData = WebClientUtil.doGet(url, null);
            subscribe.setApiApproveEndTime(new Date());
			subscribe.setApiApproveStatus(BaseConstant.API_APPROVED_NOPASS);// 更新API审核状态:不同意
            subDao.save(subscribe);
			log.debug("apim invoke request---------------------" + url);
			log.debug("apim invoke response--------------------" + jsonData);
		}
		catch (UnsupportedEncodingException e) {
			log.error("apim encode api name error");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		//return "redirect:"+iframeNameForBCMUrl;
	}

	/**
	 * 分页查询展示页面
	 * @return
	 */
	@RequestMapping("/apiApproveInfo")
	public ModelAndView apiAproInfo(String subscriber) {
		log.info("apiAproInfo");
		ModelAndView mv = new ModelAndView();
		mv.addObject("subscriber", subscriber);
		mv.setViewName("apiapproveinfo.jsp");
		return mv;
	}

	/**
	 * 分页查询展示列表结果
	 * @return
	 */
	@RequestMapping("/apiApproveInfoResult")
	@ResponseBody
	public Object apiAproInfoList(Pageable pageable,String subscriber,Integer apiApproveStatus, String apiName) {
		log.info("apiAproInfoList");
		Map<String,Object> map = new HashMap<String,Object>();
		Page<Subscribe> list;
		if (StringUtils.isEmpty(apiApproveStatus)) {
			list = subDao.findBySubscriberAndApiNameContainingOrderByApiApproveStartTimeDesc(pageable, subscriber,apiName);
		} else {
			list = subDao.findBySubscriberAndApiApproveStatusAndApiNameContaining(pageable, subscriber,apiApproveStatus, apiName);
		}
		map.put("status", 200);
		map.put("count", list.getTotalElements());
		map.put("list", list.getContent());
		return map;
	}

	/**
	 * 进入查看页面
	 * @return
	 */
	@RequestMapping("/lookAproApi")
	public ModelAndView lookAproApi(String flowInstId) {
		log.info("lookAproApi");
		Subscribe subInfo = subDao.findByProInsId(flowInstId);
		List<Record> recordList = recordDao.findByProInsId(flowInstId);
		ModelAndView model = new ModelAndView();
		model.addObject("subInfo", subInfo);
		model.addObject("recordList", recordList);
		model.setViewName("apiapplyscan.jsp");
		return model;
	}

	/**
	 * 进入流程跟踪页面
	 * @return
	 */
	@RequestMapping("/trackProccess")
	public String trackProccess(String flowInstId) {
		log.info("trackProccess");
		return "redirect:"+bpmTrackURL+"?params.pId="+flowInstId;
	}

	/**
	 * 添加流程记录
	 * @param subscribe
	 * @param taskId
	 * @param remark
	 * @return
	 */
	private void addRecord(Subscribe subscribe, String taskId, String remark, int status, String loginUser) {
		log.info("addRecord");
		Record record = new Record();
		record.setProInsId(subscribe.getProInsId());
		record.setApprover(loginUser);
		record.setTaskId(taskId);
		record.setView(remark);
		record.setCreateDate(new Date());
		record.setRecordApproveStatus(status);
		recordDao.save(record);
	}

	/**
	 * 判断返回json对象，jsop
	 * @param callback
	 * @param jsonResult
	 * @return
	 */
	private Object buildReturn(String callback, JsonResult jsonResult) {
		log.info("buildReturn");
		if (!StringUtils.isEmpty(callback)) {
			return callback + "(" + JSON.toJSONString(jsonResult) + ")";
		}
		return jsonResult;
	}

	/**
	 * bconsole数据查询接口
	 * @throws IOException
	 */
	@RequestMapping("/getApiData")
	@ResponseBody
	public Object apimGetApiData(String svcCode, String processInstanceId) {

		log.info("getApiData svcCode:" + svcCode + "," + processInstanceId);
        JSONObject jsonObject = new JSONObject();
		try {
		    if (processDefinitionId.equals(svcCode)){
                Subscribe subscribe = subDao.findByProInsId(processInstanceId);
                Publish publish =  publishDao.findByProviderNameAndApiNameAndVersion(subscribe.getProviderName(), subscribe.getApiName(), subscribe.getVersion());
                if (publish == null) {
					subscribe.setSecretData(2);
				} else {
					subscribe.setSecretData(publish.getSecretData());
				}
                subDao.save(subscribe);
                jsonObject.put("apiName",subscribe.getApiName());
                jsonObject.put("version",subscribe.getVersion());
                jsonObject.put("providerName",subscribe.getProviderName());
                jsonObject.put("tier",subscribe.getTier());
                jsonObject.put("secret",subscribe.getSecretData());
            } else if (publishModelKey.equals(svcCode)){
                Publish publish = publishDao.findByProInsId(processInstanceId);
                jsonObject.put("apiName",publish.getApiName());
                jsonObject.put("version",publish.getVersion());
                jsonObject.put("providerName",publish.getProviderName());
                jsonObject.put("tier",publish.getTier());
                jsonObject.put("secret",publish.getSecretData());
            }
		} catch (Exception e) {
			log.error("getApiData error");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return jsonObject.toJSONString();
	}

	/**
	 * 订阅审批数据查询接口
	 * @throws IOException
	 */
	@RequestMapping("/getRecordData")
	@ResponseBody
	public Object apimGetRecordData(String processInstanceId) {

		log.info("getRecordData processInstanceId =" + processInstanceId);
		JSONObject jsonObject = new JSONObject();
		try {
			if (processInstanceId != null && !processInstanceId.isEmpty()){
				Sort sort = new Sort(Sort.Direction.DESC, "id");
				Record record = null;
				List<Record> recordList = recordDao.findByProInsId(processInstanceId,sort);
				for (Record record1 : recordList) {
					record = record1;
					break;
				}
				jsonObject.put("pinsid", processInstanceId);
				jsonObject.put("approver",record.getApprover());
				jsonObject.put("view",record.getView());
			}
		} catch (Exception e) {
			log.error("getApiData error");
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return jsonObject.toJSONString();
	}
}
